<?php

use Phphub\Core\CreatorListener;
use Phphub\Forms\LabCreationForm;

class LabsController extends \BaseController implements CreatorListener
{
    protected $lab;

    public function __construct(Lab $lab)
    {
        parent::__construct();

        $this->beforeFilter('auth', ['except' => ['index', 'show', 'reports', 'members', 'evaluations', 'report_members', 'issues']]);
        $this->lab = $lab;
    }

    public function authorOrAdminPermissioinRequire($author_id)
    {
        if (! Entrust::can('manage_labs') && $author_id != Auth::id()) {
            throw new ManageLabsException("permission-required");
        }
    }

    public function index()
    {
        $classifier = $this->lab->present()->getLabClassifier();
        $labs = $this->lab->getLabsWithClassifier($classifier);
        $nodes  = Node::allLevelUp();
        $links  = Link::remember(1440)->get();

        return View::make('labs.index', compact('labs', 'nodes', 'links'));
    }

    public function create()
    {
        $node = Node::find(Input::get('node_id'));
        $nodes = Node::allLevelUp();

        return View::make('labs.create_edit', compact('nodes', 'node'));
    }

    public function store()
    {
        return App::make('Phphub\Creators\LabCreator')->create($this, Input::except('_token'));
    }

    public function show($id)
    {
        $lab = Lab::findOrFail($id);
        $creator = $lab->creator;
        $sections = $lab->sections;

        $lab->increment('view_count', 1);

        $node = $lab->node;
        $nodeLabs = $lab->getSameNodeLabs();

        return View::make('labs.show', compact('lab', 'nodeLabs', 'node', 'creator', 'sections'));
    }

    public function edit($id)
    {
        $lab = Lab::findOrFail($id);
        $this->authorOrAdminPermissioinRequire($lab->user_id);
        $nodes = Node::allLevelUp();
        $node = $lab->node;

        $lab->body = $lab->body_original;

        return View::make('labs.create_edit', compact('lab', 'nodes', 'node'));
    }

    public function append($id)
    {
        $lab = Lab::findOrFail($id);
        $this->authorOrAdminPermissioinRequire($lab->user_id);

        $markdown = new Markdown;
        $content = $markdown->convertMarkdownToHtml(Input::get('content'));

        $append = Append::create(['lab_id' => $lab->id, 'content' => $content]);

        App::make('Phphub\Notification\Notifier')->newAppendNotify(Auth::user(), $lab, $append);

        Flash::success(lang('Operation succeeded.'));
        return Redirect::route('labs.show', $lab->id);
    }

    public function update($id)
    {
        $lab = Lab::findOrFail($id);
        $data = Input::only('title', 'description', 'body', 'node_id');

        $this->authorOrAdminPermissioinRequire($lab->user_id);

        $markdown = new Markdown;
        $data['body_original'] = $data['body'];
        $data['body'] = $markdown->convertMarkdownToHtml($data['body']);
        $data['excerpt'] = Lab::makeExcerpt($data['body']);

        // Validation
        App::make('Phphub\Forms\LabCreationForm')->validate($data);

        $lab->update($data);

        Flash::success(lang('Operation succeeded.'));
        return Redirect::route('labs.show', $lab->id);
    }

    public function join()
    {
        $data['invitation_code'] = Input::get('invitation_code') ? : 'code';
        $data['lab_id'] = intval(Input::get('lab_id', 0));

        $user = Auth::user();

        $lab = Lab::findOrFail($data['lab_id']);
        if (! $lab) {
            Flash::error(lang('Lab Not Found'));
            return Redirect::route('labs.members', $lab->id);
        }

        if ($lab->invitation_code != $data['invitation_code']) {
            Flash::error(lang('Invitation Code Error'));
            return Redirect::route('labs.members', $lab->id);
        }

        $user_lab = UserLab::where('user_id', $user->id)->where('lab_id', $lab->id)->first();
        if (! $user_lab) {
            $lab->members()->attach([$user->id]);
            $lab->increment('member_count', 1);
        }
        return Redirect::route('labs.members', $lab->id);
    }

    public function refresh_code()
    {
        $data['lab_id'] = intval(Input::get('lab_id', 0));

        $user = Auth::user();

        $lab = Lab::findOrFail($data['lab_id']);
        if (! $lab) {
            Flash::error(lang('Lab Not Found'));
            return Redirect::route('labs.members', $lab->id);
        }

        $lab->invitation_code = $this->generateRandomString();
        $lab->save();

        return Redirect::route('labs.members', $lab->id);
    }

    /**
        * random alpha
     */
    function generateRandomString($length = 10) {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $charactersLength = strlen($characters);
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, $charactersLength - 1)];

        }
        return $randomString;
    }

    /**
     * ----------------------------------------
     * User Lab Vote function
     * ----------------------------------------
     */

    public function upvote($id)
    {
        $lab = Lab::find($id);
        App::make('Phphub\Vote\Voter')->labUpVote($lab);
        return Redirect::route('labs.show', $lab->id);
    }

    public function downvote($id)
    {
        $lab = Lab::find($id);
        App::make('Phphub\Vote\Voter')->labDownVote($lab);
        return Redirect::route('labs.show', $lab->id);
    }

    /**
     * ----------------------------------------
     * Admin Lab Management
     * ----------------------------------------
     */

    public function recomend($id)
    {
        $lab = Lab::findOrFail($id);
        $this->authorOrAdminPermissioinRequire($lab->user_id);
        $lab->is_excellent = (!$lab->is_excellent);
        $lab->save();
        Flash::success(lang('Operation succeeded.'));
        Notification::notify('lab_mark_excellent', Auth::user(), $lab->user, $lab);
        return Redirect::route('labs.show', $lab->id);
    }

    public function pin($id)
    {
        $lab = Lab::findOrFail($id);
        $this->authorOrAdminPermissioinRequire($lab->user_id);
        ($lab->order > 0) ? $lab->decrement('order', 1) : $lab->increment('order', 1);
        return Redirect::route('labs.show', $lab->id);
    }

    public function sink($id)
    {
        $lab = Lab::findOrFail($id);
        $this->authorOrAdminPermissioinRequire($lab->user_id);
        ($lab->order >= 0) ? $lab->decrement('order', 1) : $lab->increment('order', 1);
        return Redirect::route('labs.show', $lab->id);
    }

    public function destroy($id)
    {
        $lab = Lab::findOrFail($id);
        $this->authorOrAdminPermissioinRequire($lab->user_id);
        $lab->delete();
        Flash::success(lang('Operation succeeded.'));

        return Redirect::route('labs.index');
    }

    public function uploadImage()
    {
        if ($file = Input::file('file')) {
            $allowed_extensions = ["png", "jpg", "gif"];
            if ($file->getClientOriginalExtension() && !in_array($file->getClientOriginalExtension(), $allowed_extensions)) {
                return ['error' => 'You may only upload png, jpg or gif.'];
            }

            $fileName        = $file->getClientOriginalName();
            $extension       = $file->getClientOriginalExtension() ?: 'png';
            $folderName      = 'uploads/images/' . date("Ym", time()) .'/'.date("d", time()) .'/'. Auth::user()->id;
            $destinationPath = public_path() . '/' . $folderName;
            $safeName        = str_random(10).'.'.$extension;
            $file->move($destinationPath, $safeName);

            // If is not gif file, we will try to reduse the file size
            if ($file->getClientOriginalExtension() != 'gif') {
                // open an image file
                $img = Image::make($destinationPath . '/' . $safeName);
                // prevent possible upsizing
                $img->resize(1440, null, function ($constraint) {
                    $constraint->aspectRatio();
                    $constraint->upsize();
                });
                // finally we save the image as a new file
                $img->save();
            }

            $data['filename'] = getUserStaticDomain() . $folderName .'/'. $safeName;

            SiteStatus::newImage();
        } else {
            $data['error'] = 'Error while uploading file';
        }
        return $data;
    }

    public function evaluations($id)
    {
        $lab = Lab::findOrFail($id);
        $evaluations = $lab->evaluations()->paginate(15);

        return View::make('labs.evaluations', compact('lab', 'evaluations'));
    }

    public function sections($id)
    {
        $lab = Lab::findOrFail($id);
        $sections = $lab->sections()->get();

        return View::make('labs.sections', compact('lab', 'sections'));
    }

    public function members($id)
    {
        $lab = Lab::findOrFail($id);
        $members = $lab->members()->paginate(15);

        return View::make('labs.members', compact('lab', 'members'));
    }

    public function reports($id)
    {
        $lab = Lab::findOrFail($id);
        $reports = $lab->reports()->orderBy('section_id')->groupBy('section_id')->paginate(15);
        $rate['a'] = $lab->reports()->where('rate', 4)->orderBy('section_id')->groupBy('section_id')->limit(1)->count();
        $rate['b'] = $lab->reports()->where('rate', 3)->orderBy('section_id')->groupBy('section_id')->limit(1)->count();
        $rate['c'] = $lab->reports()->where('rate', 2)->orderBy('section_id')->groupBy('section_id')->limit(1)->count();
        $rate['d'] = $lab->reports()->where('rate', 1)->groupBy('section_id')->limit(1)->count();

        return View::make('labs.reports', compact('lab', 'reports', 'rate'));
    }

    public function report_members($id)
    {
        $lab = Lab::findOrFail($id);
        $report_members = User::query()
            ->with(['reports' => function ($query) use ($id) {
                $query->where('lab_id', $id)
                    ->withTrashed()->with('section')
                    ->orderBy('section_id')
                    ->groupBy('section_id');
            }])
            ->whereHas('labs', function($query) use ($lab) {
                $query->where('user_lab.lab_id', $lab->id);
            })
            ->paginate(15);

        return View::make('labs.report_members', compact('lab', 'report_members'));
    }

    public function issues($id)
    {
        $lab = Lab::findOrFail($id);
        $issues = $lab->issues()->paginate(15);

        return View::make('labs.issues', compact('lab', 'issues'));
    }

    /**
     * ----------------------------------------
     * CreatorListener Delegate
     * ----------------------------------------
     */

    public function creatorFailed($errors)
    {
        return Redirect::to('/');
    }

    public function creatorSucceed($lab)
    {
        Flash::success(lang('Operation succeeded.'));

        return Redirect::route('labs.show', array($lab->id));
    }
}
